package javasec.contempt.dialogs;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.UnknownHostException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.util.Date;

import javasec.contempt.Activator;
import javasec.contempt.data.SeedConnector;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.osgi.framework.Bundle;

import sun.security.x509.CertAndKeyGen;
import sun.security.x509.X500Name;

// responsible for:
// generating keys for the server and the user
// placing the default seeds in their proper location

public class ProvisionDialog extends Dialog
{
	public String username=null;
	public String hostname=null;
	
	public Text handleText=null;
	public Text hostnameText=null;
	public Text passphraseText=null;
	public Label instructionLabel=null;
	
	public boolean aborted=true;
	
	public ProvisionDialog(Shell parent)
	{
		super(parent);
	}
		
	protected void okPressed()
	{
		// get the data from the text boxes
		username=handleText.getText();
		hostname=hostnameText.getText();
		SeedConnector.globalPass=passphraseText.getText();
	
		// set the information for key generation
		String homedirPath=System.getProperty("user.home")+File.separator+".contempt";
		String seeddirPath=System.getProperty("user.home")+File.separator+".seed";
		System.out.println("using "+homedirPath+" as home directory");
		File homedir=new File(homedirPath);
		File seeddir=new File(seeddirPath);
		if(!homedir.exists())homedir.mkdir();
		if(!seeddir.exists())seeddir.mkdir();
		
	    try // generate all keys
	    {
	    	// generate the key for the user
	    	CertAndKeyGen keyPair=new CertAndKeyGen("RSA","SHA1WithRSA");
	    	
	    	instructionLabel.setText("generating 4096 bit rsa key for "+username+"..");
	    	
	    	Display.getCurrent().readAndDispatch(); // make sure the UI does not lock
	    	keyPair.generate(4096);
	    	Display.getCurrent().readAndDispatch();
	    	
	    	PrivateKey privKey=keyPair.getPrivateKey();
	    	X500Name x500Name=new X500Name("CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown");
	    	X509Certificate[] chain=new X509Certificate[1];
	    	chain[0]=keyPair.getSelfCertificate(x500Name,new Date(),86400L*365L*3L); // 3 years
	    	KeyStore keyStore=KeyStore.getInstance(KeyStore.getDefaultType());
	    	keyStore.load(null,SeedConnector.globalPass.toCharArray());
	    	keyStore.setKeyEntry(username,privKey,SeedConnector.globalPass.toCharArray(),chain);
	    	keyStore.store(new FileOutputStream(homedirPath+File.separator+"contempt-id.key"),SeedConnector.globalPass.toCharArray());
	    	
	    	// generate the key for the server
	    	CertAndKeyGen serverKeyPair=new CertAndKeyGen("RSA","SHA1WithRSA");
	    	instructionLabel.setText("generating 4096 bit rsa key for "+hostname+"...");
	    	
	    	Display.getCurrent().readAndDispatch(); // make sure the UI does not lock
	    	serverKeyPair.generate(4096);
	    	Display.getCurrent().readAndDispatch();	
	    	
	    	PrivateKey serverPrivKey=serverKeyPair.getPrivateKey();
	    	X500Name serverX500Name=new X500Name("CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown");
	    	X509Certificate[] serverChain=new X509Certificate[1];
	    	serverChain[0]=serverKeyPair.getSelfCertificate(serverX500Name,new Date(),86400L*365L*3L); // 3 years
	    	KeyStore serverKeyStore=KeyStore.getInstance(KeyStore.getDefaultType());
	    	serverKeyStore.load(null,SeedConnector.globalPass.toCharArray());
	    	serverKeyStore.setKeyEntry(hostname,serverPrivKey,SeedConnector.globalPass.toCharArray(),serverChain);
	    	serverKeyStore.store(new FileOutputStream(seeddirPath+File.separator+"seed-id.key"),SeedConnector.globalPass.toCharArray());
	    	
	    	// set the user to trust the server
			KeyStore trustedKeyStore=KeyStore.getInstance(KeyStore.getDefaultType());
			trustedKeyStore.load(null,SeedConnector.globalPass.toCharArray());
			trustedKeyStore.setCertificateEntry(hostname,serverChain[0]);
			trustedKeyStore.store(new FileOutputStream(homedirPath+File.separator+"contempt-trusted.key"),SeedConnector.globalPass.toCharArray());
			
	    	// set the server to trust the user (save one in the contempt dir for usage later)
	    	KeyStore serverTrustedKeyStore=KeyStore.getInstance(KeyStore.getDefaultType());
			serverTrustedKeyStore.load(null,SeedConnector.globalPass.toCharArray());
			serverTrustedKeyStore.setCertificateEntry(username,chain[0]);
			serverTrustedKeyStore.store(new FileOutputStream(homedirPath+File.separator+"seed-trusted.key"),SeedConnector.globalPass.toCharArray());
			serverTrustedKeyStore.store(new FileOutputStream(seeddirPath+File.separator+"seed-trusted.key"),SeedConnector.globalPass.toCharArray());
	    	
	    	// generate a blank friend store
			KeyStore friendsKeyStore=KeyStore.getInstance(KeyStore.getDefaultType());
			friendsKeyStore.load(null,SeedConnector.globalPass.toCharArray());
			friendsKeyStore.store(new FileOutputStream(homedirPath+File.separator+"contempt-friends.key"),SeedConnector.globalPass.toCharArray());
			
			// create the local database
			Class.forName("org.sqlite.JDBC");
			SeedConnector.contemptDB=DriverManager.getConnection(
				"jdbc:sqlite:"+SeedConnector.contemptPath+File.separator+"contempt.db");
			Connection conn=SeedConnector.contemptDB;
			Statement stat = conn.createStatement();
			stat.executeUpdate("drop table if exists connections;");
			stat.executeUpdate("create table connections (name, location);");
			PreparedStatement ps = conn.prepareStatement("insert into connections values (?, ?);");
			
			ps.setString(1,hostname);
			ps.setString(2,"127.0.0.1");
			ps.execute();
		}	    
	    catch(Exception e)
	    {
	    	e.printStackTrace();
	    	return;
	    }

	    //    Place the default seeds in their proper location
		try
		{
			// get a handle on the seed plugin to fetch default seeds
			Bundle seedBundle=Platform.getBundle("javasec.seed");
			
			// place SeedServer.jar
			File serverFile=new File(SeedConnector.contemptPath+File.separator+"SeedServer.jar");
			if(!serverFile.exists())
			{
				InputStream inputStream=FileLocator.openStream(seedBundle,new Path("seeds/SeedServer.jar"),false);
			
				int len;
				byte[] buf=new byte[1024];
				FileOutputStream fos=new FileOutputStream(serverFile);
				// write the file from the plugin to the contempt dir
				while(-1!=(len=inputStream.read(buf)))fos.write(buf,0,len);
			}
			
			// place TeamSeed.jar and NmapSeed.jar in .contempt/seeds
			File contemptSeedsDir=new File(SeedConnector.contemptPath+File.separator+"seeds");
			if(!contemptSeedsDir.exists())
			{
				int len;
				byte[] buf=new byte[1024];
				InputStream inputStream=null;
				FileOutputStream fos=null;
				
				contemptSeedsDir.mkdir();
				
				File teamSeedFile=new File(SeedConnector.contemptPath+File.separator+"seeds"+File.separator+"TeamSeed.jar");
				inputStream=FileLocator.openStream(seedBundle,new Path("seeds/TeamSeed.jar"),false);
				fos=new FileOutputStream(teamSeedFile);
				while(-1!=(len=inputStream.read(buf)))fos.write(buf,0,len);
				
				File nmapSeedFile=new File(SeedConnector.contemptPath+File.separator+"seeds"+File.separator+"NmapSeed.jar");
				inputStream=FileLocator.openStream(seedBundle,new Path("seeds/NmapSeed.jar"),false);
				fos=new FileOutputStream(nmapSeedFile);
				while(-1!=(len=inputStream.read(buf)))fos.write(buf,0,len);
			}
			
			// place TeamSeed.jar and NmapSeed.jar in .seed/seeds
			File seedsDir=new File(SeedConnector.contemptPath+File.separator+"seeds");
			if(!seedsDir.exists())
			{
				int len;
				byte[] buf=new byte[1024];
				InputStream inputStream=null;
				FileOutputStream fos=null;
				
				seedsDir.mkdir();
				
				File teamSeedFile=new File(seedsDir.getPath()+File.separator+"TeamSeed.jar");
				inputStream=FileLocator.openStream(seedBundle,new Path("seeds/TeamSeed.jar"),false);
				fos=new FileOutputStream(teamSeedFile);
				while(-1!=(len=inputStream.read(buf)))fos.write(buf,0,len);
				
				File nmapSeedFile=new File(seedsDir.getPath()+File.separator+"NmapSeed.jar");
				inputStream=FileLocator.openStream(seedBundle,new Path("seeds/NmapSeed.jar"),false);
				fos=new FileOutputStream(nmapSeedFile);
				while(-1!=(len=inputStream.read(buf)))fos.write(buf,0,len);
			}
			
		}
		catch(Exception e)
		{
			System.out.println("there was a problem writing the default seeds");
			e.printStackTrace();
		}
	
	    
	    aborted=false;
		super.okPressed();
	}
	
	protected Control createDialogArea(Composite parent)
	{
		Label introLabel=new Label(parent,SWT.BORDER);
		introLabel.setLayoutData(new GridData(GridData.FILL_BOTH|SWT.WRAP|SWT.CENTER));
		introLabel.setText("Welcome to contempt.\n" +
				"Private keys will be generated for you\nand the server you will be running locally.\n" +
				"The keystores are protected by the\npassphrase below.");
		introLabel.pack();
		
		Composite composite = new Composite(parent,0);
		composite.setLayout(new GridLayout(2,false));
		composite.setLayoutData(new GridData(GridData.FILL_BOTH));
	
		Label handleLabel=new Label(composite,SWT.None);
		handleLabel.setText("handle");
		handleText=new Text(composite,SWT.LEFT|SWT.BORDER);
		handleText.setText(System.getProperty("user.name"));
		handleLabel.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL));
		handleText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		handleLabel.setToolTipText("alias for personal keypair");
		handleText.setToolTipText("alias for personal keypair");
		
		Label hostnameLabel=new Label(composite,SWT.None);
		hostnameLabel.setText("server name");
		hostnameText=new Text(composite,SWT.LEFT|SWT.BORDER);
		try
		{
			// take a guess at the server's name
			hostnameText.setText(java.net.InetAddress.getLocalHost().getHostName());
		}
		catch (UnknownHostException e)
		{
			e.printStackTrace();
		}
		hostnameLabel.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL));
		hostnameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		hostnameLabel.setToolTipText("the name of the local machine");
		hostnameText.setToolTipText("the name of the local machine");
		
		Label passphraseLabel=new Label(composite,SWT.None);
		passphraseLabel.setText("passphrase");
		passphraseText=new Text(composite,SWT.LEFT|SWT.PASSWORD|SWT.BORDER);
		passphraseLabel.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL));
		passphraseText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		passphraseLabel.setToolTipText("this is the password for the java keystore files");
		passphraseText.setToolTipText("this is the password for the java keystore files");
		
		instructionLabel=new Label(parent,SWT.SINGLE|SWT.CENTER);
		instructionLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		instructionLabel.setText("key generation may take a minute");
		
		return composite;
	}
	
	protected void configureShell(Shell newShell)
	{
		super.configureShell(newShell);
		newShell.setText("generate keys");
	}
}
